home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Collection of Tools & Utilities
/
Collection of Tools and Utilities.iso
/
system
/
interc2.zip
/
INTERCEP.C
< prev
next >
Wrap
C/C++ Source or Header
|
1989-04-11
|
11KB
|
419 lines
/* intercept.c -- spawn a process and intercept BIOS and DOS
* SWI (software interrupt) calls, recording register data to
* a file.
* Demonstrates chaining interrupt handlers.
*************************************************************
* Solely for compilation under Borland's Turbo C.
*************************************************************
* Written 7/31/1987 by:
* Ned Konz
* 210 Oleeta St.
* Ormond Bch, FL 32074 (904)672-2431
* BIX:nkonz CIS:76046,223
*
* Released into the public domain by the author.
*
* Modified 4/11/1989 by:
* Russell Nelson
* 11 Grant St.
* Potsdam, NY 13676 (215)265-5655
* CIS: 70441,205 GEnie: BH01 Internet: nelson@clutx.clarkson.edu
* BITNET: nelson@clutx UUCP: uunet!clutx.clarkson.edu!nelson
*
* No copyright is claimed by Russell Nelson
*
**************************************************************/
/*************************************************************
* This program was written so I could find out quickly what
* an unknown program's interface with the outside world was.
* It does not currently handle hardware interrupts.
* What it does:
*
* 1. Runs the specified program, intercepting certain interrupts
* and recording data in memory.
* 2. Writes an intermediate file filled with Swi_info structures (binary)
* 3. Runs a program called "INTERPRE.EXE" to interpret the
* intermediate file (It's a separate program to keep
* this one small and so you can write your own.)
* It's called like this:
* interpre.exe [-l] infilename outfilename progname [args...]
* where -l denotes long output format.
**************************************************************/
#include <dos.h>
#include <stdio.h>
#include <mem.h>
#include <alloc.h>
#include <process.h>
#include <io.h>
#include <string.h>
#include <dir.h>
#include "intercept.h"
char *usage =
"[-l] [-T tmpdir] [-s maxcalls] [-o outfile] [-d datafile]\n"
"\tprogram [args...]\n"
" -l sets long format output: explanation AND register values\n"
" -T sets temporary directory for intermediate file to \"tmpdir\"\n"
" (will use TMP or TMPDIR environment vars. if found otherwise)\n"
" -s sets the maximum number of SWI records to \"maxcalls\"\n"
" -o names the output filename to \"outfile\" rather than\n"
" the default name (\"intercep.out\")\n"
" -d sets the interrupt data file to use, defaults to INTERPRE.DAT\n"
" program is the name of the program to monitor\n"
" args are any command-line arguments to be passed\n"
" to the monitored program.\n";
char *logo = "INTERCEPT -- monitor DOS and BIOS calls. By:\n"
" Ned Konz\n"
" 210 Oleeta St.\n"
" Ormond Bch, FL 32074\n"
" BIX:nkonz CIS:76046,223 (904)672-2431\n"
" 08/02/1987\n"
" Datafile option and parsing added by Russell Nelson\n";
char switchar, /* DOS parameter switch char (from int 0x21, fn 0x3700) */
sepchar = '\\'; /* DOS filename separator */
void interrupt inthandler ( Regpack r, Intpack i );
int get_swi_list(unsigned);
void install(void);
void uninstall(void);
/* the 8086/8088 INT instruction */
#define SWI_INSTRUCTION 0xCD
/* int_table[] --
* table containg numbers of interrupts we're catching
* and their old handlers
* should be sorted by most common interrupts first.
* NO HARDWARE INTERRUPTS!!!
* Note: some of these may be commented out because they tend to
* quickly fill up the output file. Uncomment and re-compile
* if you want them too.
*/
Intblock
int_table[MAX_INTS + 1]; /* leave room for a terminator */
/* swi_list[] --
* area in memory into which we store data about each SWI
*/
Swi_info huge *swi_list = NULL; /* beginning of swi_list */
Swi_info huge *swi_list_end = NULL; /* just past end of swi_list */
volatile Swi_info huge *swi_next = NULL; /* pointer to next block */
/* our single interrupt handler
* which merely records our registers and interrupt number
* in swi_list[]
* and chains to old handler.
*/
void interrupt
inthandler ( Regpack r, Intpack i )
{
/* the following variables are declared as static to get them
* off the caller's stack and to ensure that t[] is where
* we want it to be: from [BP-01] through [BP-06]
*/
static unsigned char far * caller;
static unsigned char which_int;
static IFP oldhandler;
static Intblock *ibp;
volatile unsigned t[3]; /* to move stack values down by 3 words into */
/* point to next instruction */
caller = (char far *)i.ipcs;
if (caller[-2] != SWI_INSTRUCTION) { /* was this a non-SWI? (uh-oh!) */
uninstall();
exit(-1);
}
which_int = caller[-1]; /* which SWI is this? */
if (FP_SEG(i.ipcs) > _CS && FP_SEG(i.ipcs) < 0xA000
&& swi_next < swi_list_end) {
swi_next->regs = r;
swi_next->caller = i;
swi_next->intnum = which_int;
swi_next++;
}
/* get old handler value */
for (ibp=int_table; ibp->intnum>=0 && ibp->intnum!=which_int; ibp++)
;
if (ibp->intnum < 0) /* can't happen... */
return; /* but if it does, just return "safely" */
oldhandler = ibp->oldint;
/* move all our registers down by 3 words on the stack */
movedata(_SS, FP_OFF(&r), _SS, FP_OFF(t), sizeof(Regpack));
/* supply a mock flag value with interrupts masked OFF */
r.ovl.new.flags = i.flags & ~0x0200;
/* get the address of the routine to chain to */
r.ovl.new.ipcs = oldhandler;
/* bump our frame pointer value down by 3 words --
* the stack pointer will be loaded from this new value next.
*/
_BP -= 6;
/* unstack all registers and do an IRET */
return;
}
int
get_swi_list(unsigned n)
{
if (!(swi_list = farcalloc(n, sizeof(Swi_info))))
return 0;
swi_next = swi_list;
swi_list_end = swi_list + n;
return n;
}
/* install our handler for all the named interrupts
*/
void
install()
{
Intblock *ibp;
IFPP vp;
for (ibp = int_table; ibp->intnum >= 0; ibp++) {
vp = (IFPP) MK_FP(0, ibp->intnum*4);
ibp->oldint = *vp;
disable();
*vp = inthandler;
enable();
}
}
/* un-install our handler for all the named interrupts
*/
void
uninstall()
{
Intblock *ibp;
IFPP vp;
for (ibp = int_table; ibp->intnum >= 0; ibp++) {
if (ibp->oldint != NULL) {
vp = (IFPP) MK_FP(0, ibp->intnum*4);
disable();
*vp = ibp->oldint;
enable();
}
}
}
/* Read template file into buffer, setting pointers to
* beginning of lines.
* Sets template_text, templates and ntemplates.
* Pads out interrupt IDs to 6 characters.
* Returns number of lines.
*/
int
read_template_file(char *filename)
{
FILE *ifile;
char inline[ 100 ];
Intblock *ibp = int_table;
int i;
if (! (ifile = fopen(filename, "rt")))
return 0;
while (fgets(inline, sizeof(inline), ifile)) {
if (ibp - int_table >= MAX_INTS)
return 0;
if (sscanf(inline, "%2x", &i) != 1)
continue;
if (ibp > int_table && i == (ibp-1)->intnum)
continue; /* same as the previous one */
ibp->intnum = i;
ibp->oldint = NULL;
ibp++;
}
ibp->intnum = -1; /* terminate the list */
fclose(ifile);
return 1;
}
/* output structures to intermediate file, call filter program
* return child return code (zero if OK)
*/
int
output_file(char *tmpdir, char *outfilename, int longmode,
char *progname, char *tfilename)
{
Swi_info huge *swip;
Swi_info outrec;
FILE *ofp;
char tempname[ 80 ];
int rval = 0;
sprintf(tempname, "%s%c%s", tmpdir, sepchar, "intercXXXXXX");
if (! mktemp(tempname)) {
fprintf(stderr, "%s: Bad temp file: %s\n", progname, tempname);
return -1;
}
if (! (ofp = fopen(tempname, "wb"))) {
fprintf(stderr, "%s: Can't open intermediate file %s\n",
progname, tempname);
return -1;
}
#ifdef DEBUG
fprintf(stderr, "%s: Using \"%s\" as intermediate file\n",
progname, tempname);
#endif
for (swip = swi_list; swip < (Swi_info huge *)swi_next; swip++) {
outrec = *swip;
if (fwrite(&outrec, sizeof(outrec), 1, ofp) != 1) {
fprintf(stderr, "%s: Write error on file %s\n", progname, tempname);
fclose(ofp);
unlink(tempname);
return -1;
}
}
fclose(ofp);
#ifdef DEBUG